/* **********************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This source code is subject to terms and conditions of the Shared Source License
* for DSL Editor PowerToy. A copy of the license can be found in the License.htm file
* at the root of this distribution. If you can not locate the Shared Source License
* for DSL Editor PowerToy, please obtain a copy from: http://www.codeplex.com/dsltreegrideditor/Project/License.aspx.
* By using this source code in any fashion, you are agreeing to be bound by
* the terms of the Shared Source License for DSL Editor PowerToy.
*
* You must not remove this notice, or any other, from this software.
*
* **********************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

using Microsoft.VisualStudio.Modeling;

using DslEditorPowerToy.Languages;

namespace DslEditorPowerToy.Controls.Editors
{
    public partial class TopLevelModelEditor : DslEditorControlBase
    {
        #region Constructors
        public TopLevelModelEditor() : base()
        {
            InitializeComponent();

            InitialiseControls();
        }
        #endregion

        #region Protected Methods
        /// <summary>
        /// Gets the list of selectable items in the control
        /// </summary>
        protected override System.Collections.ICollection SelectableComponents
        {
            get
            {
                //Return list of the selected contained objects
                List<object> items = new List<object>();
                foreach (ListViewItem item in this.itemListView.Items)
                {
                    if (true == item.Selected)
                        items.Add(item.Tag);
                }
                return items;
            }
        }
        /// <summary>
        /// Gets whether the specified componet is currently selected
        /// </summary>
        /// <param name="component"></param>
        /// <returns></returns>
        protected override bool IsComponentSelected(object component)
        {
            //Detrmine if component represents contained object, that is now selected
            foreach (ListViewItem item in this.itemListView.Items)
            {
                if (component == item.Tag)
                    return (item.Selected);
            }

            return false;
        }
        public override void OnRootElementChanged(Microsoft.VisualStudio.Modeling.ModelElement rootElement)
        {
            base.OnRootElementChanged(rootElement);

            //Populate list again (only do this if we have a root element)
            if (null != rootElement)
                PopulateList();
        }
        #endregion

        #region Control Handlers
        /// <summary>
        /// Handles an item changing selection
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void itemListView_ItemSelectionChanged(object sender, System.Windows.Forms.ListViewItemSelectionChangedEventArgs e)
        {
            base.OnSelectionChanged();
            InitialiseControlState();
        }
        /// <summary>
        /// Handles the click of the 'Add New' button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void addButton_Click(object sender, EventArgs e)
        {
            AddNewItem();
        }
        /// <summary>
        /// Handles the click of the 'Remove' button
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void deleteButton_Click(object sender, EventArgs e)
        {
            DeleteItems();
        }
        private void refreshButton_Click(object sender, EventArgs e)
        {
            RefreshList();
        }
        private void viewsButton_Click(object sender, EventArgs e)
        {
            ToolStripButton button = sender as ToolStripButton;
            if (null != button)
                ToggleView();
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Initialises controls in control
        /// </summary>
        private void InitialiseControls()
        {
            //Initialise ocntrol state
            InitialiseControlState();
        }
        private void InitialiseControlState()
        {
            //Set control state
            this.addButton.Enabled = true;
            this.deleteButton.Enabled = (this.itemListView.SelectedItems.Count > 0);
        }
        /// <summary>
        /// Populates list with children elements of the model
        /// </summary>
        private void PopulateList()
        {
            //Get the meta info for the roots children
            DomainClassInfo childClassInfo = MetaModelHelper.GetFirstEmbeddedChildInfo(this.RootElement);

            //Get the child items from the root
            LinkedElementCollection<ModelElement> childItems = MetaModelHelper.GetFirstEmbeddedRelationshipChildren(this.RootElement);

            //Add branch info to list for reference
            this.itemListView.Tag = new BranchInfo(this.RootElement, childClassInfo);

            //Setup columns
            ReadOnlyCollection<DomainPropertyInfo> propertiesInfo = MetaModelHelper.GetAllPropertyInfo(childClassInfo);
            DomainPropertyInfo namePropertyInfo = childClassInfo.NameDomainProperty;
            this.itemListView.Columns.Clear();

            //Check for a name domain property
            if (null != namePropertyInfo)
                this.itemListView.Columns.Add(namePropertyInfo.Name, namePropertyInfo.DisplayName);
            else
                this.itemListView.Columns.Add("Token", "Token");
            //Add all other properties
            foreach (DomainPropertyInfo propertyInfo in propertiesInfo)
            {
                //Add only if not name property
                if (((null != namePropertyInfo)
                    && (propertyInfo != namePropertyInfo))
                    || (null == namePropertyInfo))
                this.itemListView.Columns.Add(propertyInfo.Name, propertyInfo.DisplayName);
            }

            //Add list items
            this.itemListView.Items.Clear();
            foreach (ModelElement element in childItems)
                AddModelElementToList(element);

            //Prepare default view
            this.itemListView.AutoResizeColumns((childItems.Count > 0) ? ColumnHeaderAutoResizeStyle.ColumnContent : ColumnHeaderAutoResizeStyle.HeaderSize);
            if (this.itemListView.Items.Count > 0)
                this.itemListView.Items[0].Selected = true;

            //Initialise controls
            InitialiseControlState();
        }
        /// <summary>
        /// Adds a new item to the list
        /// </summary>
        private void AddNewItem()
        {
            if (null == this.RootElement)
                return;

            BranchInfo branchInfo = this.itemListView.Tag as BranchInfo;

            //Add new element to parent class
            ModelElement element = MetaModelHelper.AddNewChildToFirstEmbeddingParent(this.RootElement, branchInfo.ChildClassInfo);
            if (null == element)
                return;

            //Add item to list
            AddModelElementToList(element);

            //Initialise ocntrol state
            InitialiseControlState();
        }
        /// <summary>
        /// Deletes items from the list
        /// </summary>
        private void DeleteItems()
        {
            if (null == this.RootElement)
                return;

            if (0 == this.itemListView.SelectedItems.Count)
                return;

            BranchInfo branchInfo = this.itemListView.Tag as BranchInfo;
            foreach (ListViewItem item in this.itemListView.SelectedItems)
            {
                //Get element
                ModelElement element = item.Tag as ModelElement;
                if (null == element)
                    continue;

                //Delete element from parent class
                MetaModelHelper.RemoveChildFromEmbeddingParent(element);

                //Remove item from list
                item.Remove();
            }

            //Initialise ocntrol state
            InitialiseControlState();
        }
        /// <summary>
        /// Refreshes list
        /// </summary>
        private void RefreshList()
        {
            PopulateList();
        }
        /// <summary>
        /// Adds a new item to the list view
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        private void AddModelElementToList(ModelElement element)
        {
            BranchInfo branchInfo = this.itemListView.Tag as BranchInfo;
            if (null == branchInfo)
                return;

            //Get name display text
            string elementNameText = MetaModelHelper.GetName(element);
            if (true == string.IsNullOrEmpty(elementNameText))
                elementNameText = "(empty)";

            //Populate a list item
            ListViewItem listItem = new ListViewItem(elementNameText, 0);
            listItem.Tag = element;

            //Populate columns of each item
            ReadOnlyCollection<DomainPropertyInfo> propertiesInfo = MetaModelHelper.GetAllPropertyInfo(branchInfo.ChildClassInfo);
            DomainPropertyInfo namePropertyInfo = branchInfo.ChildClassInfo.NameDomainProperty;
            foreach (DomainPropertyInfo propertyInfo in propertiesInfo)
            {
                //Add only if not name property
                if (((null != namePropertyInfo)
                    && (propertyInfo != namePropertyInfo))
                    || (null == namePropertyInfo))
                {
                    object propValue = propertyInfo.GetValue(element);
                    listItem.SubItems.Add((null != propValue) ? propValue.ToString() : null);
                }
            }
            //Add item to list
            this.itemListView.Items.Add(listItem);
        }
        /// <summary>
        /// Toggles the view of the list control
        /// </summary>
        private void ToggleView()
        {
            View currentView = this.itemListView.View;

            View newView = View.Details;
            switch (currentView)
            {
                case View.Details:
                    newView = View.LargeIcon;
                    break;

                default:
                    newView = View.Details;
                    break;
            }

            //Toggle view
            this.itemListView.View = newView;
        }
        #endregion
    }

    /// <summary>
    /// A class to contain info about the data source
    /// </summary>
    internal class BranchInfo
    {
        private ModelElement _parentElement = null;
        private DomainClassInfo _childClassInfo = null;

        #region Constructors
        public BranchInfo(ModelElement parentElement, DomainClassInfo childClassInfo)
        {
            this._parentElement = parentElement;
            this._childClassInfo = childClassInfo;
        }
        #endregion

        #region Public Properties
        public ModelElement ParentElement
        {
            get
            {
                return this._parentElement;
            }
        }
        public DomainClassInfo ParentClassInfo
        {
            get
            {
                return this._parentElement.GetDomainClass();
            }
        }
        public DomainClassInfo ChildClassInfo
        {
            get
            {
                return this._childClassInfo;
            }
        }
        #endregion
    }
}
